<?php

namespace App\Logics;


use App\Models\Course;
use App\Models\CourseCycle;
use App\Models\CourseTimes;
use App\Service\Base\Logic;
use Illuminate\Support\Carbon;

class CourseTimeLogic extends Logic
{

    // 课程的课时
    public function initialize()
    {
        parent::initialize();

        $this->model = '';
    }

    // 列表
    // 添加
    // 修改
    // 软删除

    // 列表查询
    public function onLists($myUid = 0)
    {
        $opt   = $this->option();
        $page  = $opt->getData('page', 1, 'intval');
        $rows  = $opt->getData('rows', 15, 'intval');
        $start = ($page - 1) * $rows;

        // 模型 和 查询
        $option = $this->option();
        $where  = [];
        $bang   = [];
        $c_id   = $option->getData('course_id', 0, 'intval');
        $uid    = $option->getData('uid', 0, 'intval');
        $s_id   = $option->getData('student_id', 0, 'intval');
        $s_time = $option->getData('start_time', 0, 'intval');
        $e_time = $option->getData('end_time', 0, 'intval');
        $isPage = $option->getData('is_count', 0, 'intval');  // 是否需要翻页
        if($c_id){
            $bang[]  = 'course_id';
            $where[] = ['course_id', '=', $c_id];
        }
        if($uid){
            $bang[]  = 'uid';
            $where[] = ['uid', '=', $uid];
        }
        if($myUid){
            $bang[]  = 'uid';
            $where[] = ['uid', '=', $myUid];
        }
        if($s_id){
            $bang[]  = 'student_id';
            $where[] = ['student_id', '=', $s_id];
        }
        if($s_time){
            $bang[]  = 'ctime';
            $where[] = ['ctime', '>=', $s_time];
        }
        if($e_time){
            $bang[]  = 'ctime';
            $where[] = ['ctime', '<=', $e_time];
        }

        // 模型
        $model  = new CourseTimes();
        $KCache = $model->cacheKey('lists', $where);
        $result = $model->cacheClass()->getCache($KCache);
        // 检查是否已经绑定
        if(!empty($result)){
            if($isPage){
                if(!empty($result['list'])){
                    $model->checkBangList($result['list'], $KCache);
                }
            } else{
                $model->checkBangList($result, $KCache);
            }
        }

        // ->bangField($bang)
        if(empty($result)){
            if($isPage){
                $result = $model->listPage($where, $page, $rows, "id DESC");
            } else{
                $result = $model->getList($where, $rows, "id DESC", $start);
                $result = is_object($result) ? $result->toArray() : $result;
            }
            /*if($where != false){
                $model->addCacheList($lists, $KCache, $result, 'list');
            }*/
        }

        return $result;
    }

    //   上课时间
    public function onShow()
    {
        $option = $this->option();
        $c_id   = $option->getData('course_id', 0, 'intval');
        $_id    = $option->getData('id', 0, 'intval');  // 如果是学员，看自己的课程信息

        // 课程时间
        $timesDb = new CourseTimes();
        $times   = $timesDb->bangField(['course_id'])->oneFind(['id' => $_id]);
        if(empty($times)){
            return $this->_returnFail($timesDb->getError());
        }

        return $times;
    }


    // 直接删除
    public function onDelete($myUid)
    {
        $opt = $this->option();
        $_id = $opt->getData('id', 0, 'intval');
        if(empty($_id)){
            return $this->_returnFail('请指定删除记录');
        }

        $where  = ['id' => $_id, 'uid' => $myUid];
        $model  = new CourseTimes();
        $result = $model->isCache(true)->oneDelete($where);
        if($result === false){
            return $this->_returnFail($model->getError());
        }

        return $result;
    }


    // 直接删除
    public function batchDelete($myUid)
    {
        $opt  = $this->option();
        $_ids = $opt->getData('ids', [], 'is_array');
        if(empty($_ids)){
            return $this->_returnFail('请指定删除记录');
        }

        $where = ['uid' => $myUid];
        $model = new CourseTimes();
        $list  = $model->whereIn('id', $_ids)->where($where)->get();  //->recycle()
        if($list->isEmpty()){
            return $this->_returnFail('你要删除的数据不存在！！');
        }

        // 缓存操作
        $model->deleteCacheList($list);
        $res = $model->whereIn('id', $_ids)->where($where)->delete();  //->recycle()

        return $res;
    }

    // 改变（直接修改，软删除，改变状态，排序）
    public function onEdit($myUid)
    {
        $opt = $this->option();
        $_id = $opt->getData('id', null, 'intval');
        if(empty($_id)){
            return $this->_returnFail('请指定修改的ID编号！');
        }

        $data = [
            //'id'         => $opt->getData("id", null, "trim"),
            //'uid'        => $myUid,
            'uid'        => $opt->getData("uid", null, "intval"),
            'course_id'  => $opt->getData("course_id", null, "intval"),
            'number'     => $opt->getData("number", null, "intval"),
            'start_time' => $opt->getData("start_time", null, "strtotime"),
            'end_time'   => $opt->getData("end_time", null, "strtotime"),
            //'ctime'      => $opt->getData("ctime", null, "trim"),
            //'mtime'      => $opt->getData("mtime", null, "trim"),
        ];
        if($data['end_time'] && ($data['end_time'] <= $data['start_time'])){
            return $this->_returnFail('结束时间不能小于开始时间！');
        }

        $data = $this->filterNull($data);
        if(empty($data)){
            return $this->_returnFail('请添加需要保存的数据！');
        }

        // 组合数据
        $where = ['id' => $_id, 'uid' => $myUid];
        $model = new CourseTimes();
        $data  = $model->checkData($data, $where);
        if($data === false){
            return $this->_returnFail('请添加需要保存的数据！');
        }

        // 验证
        $result = $model->checkRules($data, 'edit');
        if($result === false){
            return $this->_returnFail($model->getError());
        }

        // 保存
        //  保存的时候：保存时间
        $result = $model->oneEdit($where, $data);
        if($result === false){
            return $this->_returnFail($model->getError());
        }

        return $result;
    }

    // 树状
    public function onAdd($myUid)
    {
        $opt  = $this->option();
        $data = [
            //'id'         => $opt->getData("id", null, "trim"),
            'uid'        => $myUid,
            'course_id'  => $opt->getData("course_id", null, "intval"),
            'number'     => $opt->getData("number", null, "intval"),
            'start_time' => $opt->getData("start_time", null, "strtotime"),
            'end_time'   => $opt->getData("end_time", null, "strtotime"),
            //'ctime'      => $opt->getData("ctime", null, "trim"),
            //'mtime'      => $opt->getData("mtime", null, "trim"),
        ];

        if($data['end_time'] && ($data['end_time'] <= $data['start_time'])){
            return $this->_returnFail('结束时间不能小于开始时间！');
        }

        // 测试时间应该到当天晚上
        $data = $this->filterNull($data);
        if(empty($data)){
            return $this->_returnFail('请添加需要保存的数据！');
        }

        // 组合数据
        $model = new CourseTimes();
        $data  = $model->checkData($data);
        if($data === false){
            return $this->_returnFail('请添加需要保存的数据！');
        }

        // 验证
        $result = $model->checkRules($data, 'add');
        if($result === false){
            return $this->_returnFail($model->getError());
        }

        // 保存
        $result = $model->oneAdd($data);
        if($result === false){
            return $this->_returnFail($model->getError());
        }

        return $result;
    }



    #########################################################################################################
    // 根据周期计算课时
    public function makeTimeByCycle($course_id)
    {
        // 1、获取课程信息
        $info = (new Course())->where('id', $course_id)->first();
        if(empty($info)){
            return $this->_returnFail('没有找到课程！');
        }
        if(time() > $info['start_time']){
            return $this->_returnFail('课程已经开始，不能在生成课时信息！');
        }

        // 2、获取周期信息
        $info   = $info->toArray();
        $uid    = $info['uid'];
        $cycles = (new CourseCycle())->where('course_id', $course_id)->get()->toArray();
        if(empty($cycles)){
            return $this->_returnFail('没有找到该课程的周期！');
        }

        // 3、根据周期计算时间
        $times = $this->makeTimeGetCycle($info, $cycles);
        if(empty($times)){
            return $this->_returnFail('没有找到该课程的上课时间！');
        }

        // 4、保存课程时间
        $this->makeTimeSaveTimes($uid, $course_id, $times);

        return true;
    }


    #########################################################################################################
    ## 根据周期计算课时调用方法
    // 3、根据周期计算时间
    protected function makeTimeGetCycle($info, $cycles)
    {
        $start  = $info['start_time'];
        $end    = $info['end_time'];
        $number = $info['times'];  // 上课总课时
        $today  = Carbon::now();

        // 时间处理测试
        //$dayOfWeekIso = $today->dayOfWeek; // 输出可能是 1 到 7
        //$nextTuesday  = $today->next(Carbon::TUESDAY);  // ->next 参数是0-6
        $allTimes = [];
        foreach($cycles as $item){
            $_type   = $item['cycle'];
            $_number = $item['number'];
            $_hour   = $item['hour'];
            $_minute = $item['minute'];

            // 数据判断
            if(($_hour > 23) || ($_hour < 0)){
                continue;
            }
            if(($_minute > 60) || ($_minute < 0)){
                continue;
            }
            if($_type == 'week'){
                if(($_number > 7) || ($_number < 0)){
                    continue;
                }
            } elseif($_type == 'month'){
                if(($_number > 31) || ($_number < 0)){
                    continue;
                }
            }

            // 整理那些天有课
            $_times = [];  // 计算有课的那些天
            if($_type == 'week'){
                // 判断时间
                // 下次时间+7天 在判断时间
                //$_nextDate = $today->next($_number - 1);
                $_times = $this->makeTimeJisuan($today, $start, $end, $_number, 'week');
            } elseif($_type == 'month'){
                // 计算第一个时间
                $_next  = $today->startOfMonth()->addDays($_number - 1);
                $_stamp = $_next->format('U');
                if(($_stamp > $start) && ($_stamp < $end)){
                    $_times[] = $_stamp;
                }

                // 计算 下次时间
                $_times2 = $this->makeTimeJisuan($_next, $start, $end, $_number, 'month');
                $_times  = array_merge($_times, $_times2);
            }

            // 整理有课的那些天的上课具体时间
            if($_times){
                foreach($_times as $_time){
                    if($item['start_time']){
                        $allTimes[] = $_time + $item['start_time'];
                        //$allTimes[] = $_time + $item['end_time'];
                    } else{
                        $allTimes[] = $_time + $_hour * 3600 + $_minute * 60;
                    }
                }
            }
        }

        // 整理时间 按时间排序
        sort($allTimes);

        // 去除多余的课时
        $count = count($allTimes);
        if($count > $number){
            $allTimes = array_slice($allTimes, 0, $number);
        }

        return $allTimes;
    }

    // 4、保存课程时间
    protected function makeTimeSaveTimes($uid, $course_id, $times)
    {
        if(empty($times)){
            return true;
        }

        // 整理需要保存的数据
        $time   = time();
        $insert = [];
        foreach($times as $_key => $_time){
            $insert[] = ['uid' => $uid, 'course_id' => $course_id, 'number' => $_key + 1, 'start_time' => $_time, 'ctime' => $time, 'mtime' => $time,];
        }

        // 清理数据
        $timeDb = new CourseTimes();
        $timeDb->where('course_id', $course_id)->delete();

        // 执行保存
        $timeDb->insert($insert);
        $timeDb->deleteCacheList($insert);

        return true;
    }

    // 3.1 计算时间
    protected function makeTimeJisuan($today, $start, $end, $number, $type = 'week')
    {
        // 计算下一个时间
        $times = [];
        if($type == 'week'){
            $_next = $today->next($number - 1);
        } elseif($type == 'month'){
            $_next = $today->addMonth();;
        }

        // 对比时间戳
        $_stamp = $_next->format('U');
        if(($_stamp > $start) && ($_stamp < $end)){
            $times[] = $_stamp;
        }

        // 继续
        if($_stamp < $end){
            $times2 = $this->makeTimeJisuan($_next, $start, $end, $number);
            $times  = array_merge($times, $times2);
        }

        return $times;
    }

    #########################################################################################################

}


